package com.kin207.netty.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.kin207.netty.listener.Listener;
import com.kin207.netty.listener.ListenerConfig;

public class ServerContext {
	final static Logger logger = LoggerFactory.getLogger(ServerContext.class);
	
	private String config;
	
	private JSONObject configObject;
	
	private Map<String,CBean> beans = new HashMap();
	
	private List<CServer> servers = new ArrayList();
	
	private Map<String,List<CListener>> listeners = new HashMap();
	
	public ServerContext(){
		
	}
	
	public ServerContext(String config) {
		super();
		this.config = config;
		this.configObject = JSON.parseObject(config);
	}
	
	public ServerContext(JSONObject configObject) {
		super();
		this.config = configObject.toJSONString();
		this.configObject = configObject;
	}
	
	public ServerContext build(){
		buildBeans();
		buildListeners();
		buildServers();
		return this;
	}
	
	public void buildServers(){
		JSONArray serverArr = configObject.getJSONArray("servers");
		if(serverArr==null){
			return ;
		}
		List<CServer> serverList = serverArr.toJavaList(CServer.class);
		
		servers = serverList;
	}
	
	public void buildBeans(){
		JSONArray beanArr = configObject.getJSONArray("beans");
		if(beanArr==null){
			return ;
		}
		List<CBean> beanList = beanArr.toJavaList(CBean.class);
		for(CBean item : beanList){
			String name = item.getName();
			if(name==null){
				String cn = item.getClassName();
				name = cn.indexOf(".")>-1?cn.substring(cn.lastIndexOf(".")+1):cn;
				name = Character.toLowerCase(name.charAt(0))+name.substring(1);
			}
			beans.put(name==null?item.getClassName():name, item);
		}
	}
	
	public void buildListeners(){
		JSONArray serverArr = configObject.getJSONArray("listeners");
		if(serverArr==null){
			return ;
		}
		List<CListener> listenerList = serverArr.toJavaList(CListener.class);
		for(CListener item : listenerList){
			List list = listeners.get(item.getType());
			if(list==null){
				list = new ArrayList();
				listeners.put(item.getType(), list);
			}
			list.add(item);
		}
	}
	
	public List<Listener> getListenerList(String type){
		List<CListener> clists = listeners.get(type);
		List<Listener> result = null;
		if(clists!=null){
			result = new ArrayList(clists.size());
			for(CListener item : clists){
				Map initCfg = item.getInitConfig();
				ListenerConfig cfg = new ListenerConfig(item.getInitConfig());
				try {
					Listener listener = item.getListener();
					listener.initialize(cfg);
					result.add(listener);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
					throw new RuntimeException(e);
				}
			}
		}
		return result;
	}
	
	public static ServerContext create(String filePath){
		return create(new File(filePath));
	}
	
	public static ServerContext create(File file){
		try {
			return create(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException(e);
		}
	}
	
	public static ServerContext create(InputStream input){
		String str = null;
		try {
			str = IOUtils.toString(input, "UTF-8");
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException(e);
		}
		return new ServerContext(str).build();
	}
	
	public Object getBean(String name){
		try {
			CBean bean = beans.get(name);
			if(bean==null){
				return null;
			}
			return bean.get();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException(e);
		} 
	}
	
	public <T> List<T> getBeans(Class<T> clazz){
		List<T> result = new ArrayList();
		try {
			for(CBean item : beans.values()){
				if(clazz.isAssignableFrom(item.getClazz())){
					result.add((T)item.get());
				}	
			}
		}  catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException(e);
		} 
		return result;
	}
	
	public <T> T getBean(String name, Class<T> clazz){
		return (T)getBean(name);
	}
	
	public <T> T getBean(Class<T> clazz){
		T result = null;
		for(CBean item : beans.values()){
			if(clazz.isAssignableFrom(item.getClazz())){
				try {
					result = (T)item.get();
				}  catch (Exception e) {
					logger.error(e.getMessage(), e);
					throw new RuntimeException(e);
				} 
				break;
			}	
		}
		return result;
	}

	public String getConfig() {
		return config;
	}
	public void setConfig(String config) {
		this.config = config;
	}
	public JSONObject getConfigObject() {
		return configObject;
	}
	public void setConfigObject(JSONObject configObject) {
		this.configObject = configObject;
	}

	public Map<String, CBean> getBeans() {
		return beans;
	}

	public void setBeans(Map<String, CBean> beans) {
		this.beans = beans;
	}

	public List<CServer> getServers() {
		return servers;
	}

	public void setServers(List<CServer> servers) {
		this.servers = servers;
	}

	public Map<String, List<CListener>> getListeners() {
		return listeners;
	}

	public void setListeners(Map<String, List<CListener>> listeners) {
		this.listeners = listeners;
	}
	
	
	
}
